/**
 * Create by AdminUser
 * Description: senior_utils
 * Date: 2022/7/28 11:21
 * Update: 2022/7/28 11:21
 */

/*
 * 类型检测 typeOf
 * type(xxx)
 * */
export const typeOf = (operand) => {
  const toString = Object.prototype.toString;
  let type = toString.call(operand).split(' ')[1];
  type = type.substring(0, type.length - 1).toLowerCase();
  return type;
};

/*
 * 函数柯里化
 * const xxx = curry(xxx, 1);
 * */
export const curry = (fn, ...args) => {
  const len = fn.length;
  return function (that) {
    const anonArgs = Array.prototype.slice.call(arguments);
    Array.prototype.push.apply(args, anonArgs);
    if (args.length < len) {
      return curry.call(that, fn, ...args);
    } else {
      return fn.apply(that, args);
    }
  };
};

/*
 * 深拷贝
 * const copy = deepClone(obj);
 * */
export const deepClone = (target, map = new WeakMap()) => {
  if (target === null || typeof target !== 'object') {
    return target;
  }

  if (map.get(target)) {
    return target;
  }

  const Ctor = target.constructor;
  const ctorName = Ctor.name;
  if (/^(RegExp|Date|Number|String|Boolean|Error)$/i.test(ctorName)) {
    return new Ctor(target);
  }

  if (ctorName === 'Symbol') {
    return Object(Object.prototype.valueOf.call(target));
  }

  if (ctorName === 'Map') {
    let cloneMap = new Map();
    map.set(target, true);
    target.forEach((value, key) => {
      cloneMap.set(deepClone(key, map), deepClone(value, map));
    });
    return cloneMap;
  }

  if (ctorName === 'Set') {
    let cloneSet = new Set();
    map.set(target, true);

    target.forEach((value) => {
      cloneSet.add(deepClone(value, map));
    });
    return cloneSet;
  }

  map.set(target, true);

  let cloneResult = Object.prototype.toString.call(target) === '[object Array]' ? [] : {};

  Object.getOwnPropertyNames(target).forEach((key) => {
    cloneResult[key] = deepClone(target[key], map);
  });

  return cloneResult;
};

/*
 * 扁平数据结构转树状结构
 * flatToTree([{id: "1000",pid:xx,label: "山西省",}])
 * */
export const flatToTree = (target, options = { idKey: 'id', pidKey: 'pid', childrenKey: 'children', topVal: '' }) => {
  const copyFlat = Array.prototype.slice.call(target);
  const record = Object.create(null);
  const defaultOpts = Object.assign(
    {
      idKey: 'id',
      pidKey: 'pid',
      childrenKey: 'children',
      topVal: '',
    },
    options,
  );
  const { idKey, pidKey, childrenKey, topVal } = defaultOpts;
  const tree = [];
  for (let i = 0, len = copyFlat.length; i < len; i++) {
    const item = copyFlat[i];
    const { [idKey]: idVal, [pidKey]: pidVal } = item;
    if (record[idVal]) {
      item[childrenKey] = record[idVal];
    } else {
      item[childrenKey] = record[idVal] = [];
    }

    if (pidVal && pidVal !== topVal) {
      if (!record[pidVal]) {
        record[pidVal] = [];
      }
      record[pidVal].push(item);
    } else {
      tree.push(item);
    }
  }
  return tree;
};

/*
* 树状结构扁平化
* const provinceFlat = treeToFlat([
 {id: "1000",
   label: "山西省",
    children: [
      {
        id: "1001",
        pid: "1000",
        label: "太原市",]
 });
* */
export const treeToFlat = (target, subsetKey = 'children') => {
  const copyTree =
    Object.prototype.toString.call(target) === '[object Array]' ? Array.prototype.slice.call(target) : [target];

  const flat = [];

  while (copyTree.length) {
    const node = copyTree.shift();
    const { [subsetKey]: children, ...rest } = node;
    flat.push(rest);
    if (children) {
      Array.prototype.push.apply(copyTree, node.children);
    }
  }

  return flat;
};

/*
 * 获取树状结构节点
 * const province1201 = getNodeFromTree(Tree:[], "1201");
 * */
export const getNodeFromTree = (target, mark, options = { idKey: 'id', childrenKey: 'children' }) => {
  const copyTree =
    Object.prototype.toString.call(target) === '[object Array]' ? Array.prototype.slice.call(target) : [target];
  const defaultOpts = Object.assign(
    {
      idKey: 'id',
      childrenKey: 'children',
    },
    options,
  );
  const { idKey, childrenKey } = defaultOpts;

  while (copyTree.length) {
    const node = copyTree.shift();
    if (node[idKey] === mark) {
      return node;
    }
    if (node[childrenKey]) {
      Array.prototype.push.apply(copyTree, node.children);
    }
  }
  return null;
};
